<?php
/*
 *      Aether
 * 	PHP Framework
 *      
 *      Copyright 2010 Panthr - http://www.madebypanthr.com/
 *      
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 3 of the License, or
 *      (at your option) any later version.
 *      
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *      
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */

define('AETHER_WEB',0);
define('AETHER_CLI',1);
define('AETHER_BOTH',2);

class aether {
	protected $rawUrl;
	protected $url;
	protected $mode;
	public $config;
	public $helpers;
	public $models;
	public $controller;
	public $cache;
	protected $routeVars;
	protected $routeHandler;
	public $errorHandler;
	public $loader;
	protected $module;

	public function __construct($url, $mode) {
		//Load libraries
		$this->load('lib/standard');
		$this->load('lib/array');

		//Load constants
		$this->load('constants');
		require('core/constants.php');
		require('app/constants.php');
		
		//Let's load the configurations
		$this->load('thirdParty/spyc');
		$this->load('classes/configuration');
		$this->config = new configuration($this);
		$this->config->loadAll(array('core', 'app'));

		//Create debugger
		$this->load('classes/log');
		if($this->config->get('general', 'appMode')==AETHER_DEVELOPMENT&&$this->config->get('general', 'debug')) {
			$this->debug = new log(array('fn'=>'app/logs/debug.txt')); 
		} else {
			$this->debug = new blankLog();
		}
		
		$this->debug->write('');
		$this->debug->write('**********************************');
		$this->debug->write('Debugger successfully initialized');
		$this->debug->write('URL: '.$this->url);
		

		//Create error handler
		$this->load('classes/errorHandler');
		$this->errorHandler = new errorHandler(array(
			'mode' => $mode,
			'appMode' => $this->config->get('general', 'appMode'),
			'webRoot' => $this->config->get('general', 'webRoot'),
			'logFile' => 'app/logs/error.txt'
		));
		$this->debug->write('Error handler created');

		//Load resource loader
		$this->load('classes/loader'); 
		$this->loader = new loader($this);

		//Load some general files
		$this->load('classes/predicate');
		$this->load('classes/constraint');

		if($this->config->get('general', 'appMode')==AETHER_DEVELOPMENT OR $this->config->get('general', 'appMode')==AETHER_STAGING) {
			error_reporting(E_ALL); //Display all errors
		}

		//Load cache controls
		switch($this->config->get('cache', 'type')) {
			case 'file':
				$this->load('classes/fileCache');
				$this->cache = new fileCache($this);
				break;
			case 'none':
				$this->load('classes/noCache');
				$this->cache = new noCache();
				break;
		}

		$this->mode = $mode;

		if($url!='/'&&$url[0]=='/') {
			$url = substr($url, 1);
		}
		if(substr($url, strlen($url)-1)!='/') {
			$url .= '/';
		}

		$this->rawUrl = $url;

		if(
			(
				($this->config->get('general', 'urlToPhpWeb')&&$this->mode==AETHER_WEB) ||
				($this->config->get('general', 'urlToPhpCli')&&$this->mode==AETHER_CLI)
			) &&
			(
				(isset($_GET['urlToPhp']) && (bool) $_GET['urlToPhp']===false) ||
				!isset($_GET['urlToPhp'])
			)
		) {
			$this->url = urlToPHP($url);
		} else {
			$this->url = $url;
		}
		
				
		//Let's connect to the database.  Currently there's no support for multiple dbs
		if($this->config->get('database', 'hasDatabase')) {
			$this->load('database/interface');
			$this->load('database/'.$this->config->get('database', 'type'));
			$this->db = new dbHandler($this);
			$this->debug->write('Database connected');
		}
		
		//Now lets process the URL with routes
		$this->load('classes/route');
		$this->routeHandler = new routeHandler($this->mode, $this->config->get('globals', 'plugins'));
		if(!($this->routeVars = $this->routeHandler->checkRoutes($this->url))) {
			$this->errorHandler->trigger('noMatchingRoute', array('url'=>$this->url));
		}
		$this->debug->write('Route processed');

		//Load the classes
		$this->load('classes/helperHolder');
		$this->load('classes/modelHolder');
		$this->load('classes/helperBase');
		$this->load('classes/modelBase');
		$this->load('classes/stabilityLayer');
		$this->load('classes/stabilityLayerUpdates');
		$this->load('classes/controllerBase');
		$this->load('classes/view');
		$this->load('classes/data');
		
		//Find the module, and load up the controller
		if(isset($this->routeVars['plugin'])) {
			$this->module = $this->routeVars['plugin'];
			$this->config->loadAll(array($this->routeVars['plugin']));
			$this->loader->load($this->routeVars['plugin'].':controller/'.$this->routeVars['controller']);
		} else {
			if($this->loader->load('app:controller/'.$this->routeVars['controller'], null, null, false)) {
				$this->module = 'app';
			} else if($this->loader->load('core:controller/'.$this->routeVars['controller'], null, null, false)) {
				$this->module = 'core';
			} else {
				$this->errorHandler->trigger('noMatchingController', array('controller' => $this->routeVars['controller']));
			}
		}
		
		//Load classes
		$this->loader->loadArray($this->config->get('globals', 'classes'), 'app', 'class');
		$this->debug->write('Classes loaded');

		//Load the holders
		$this->helpers = new helperHolder($this);
		$this->models = new modelHolder($this);
			
		//Load the helpers and models
		$this->loader->loadArray($this->config->get('globals', 'helpers'), $this->module, 'helper');
		$this->helpers->init(); //Initialize helpers after global helpers have been called
		$this->debug->write('Helpers loaded');
		$this->loader->loadArray($this->config->get('globals', 'models'), $this->module, 'model');
		$this->debug->write('Models loaded');
		
		//Load the filters
		$this->load('classes/filterHolder');
		$this->beforeFilter = new filterHolder($this);
		$this->beforeFilter->addArray($this->config->get('globals', 'beforeFilters'));
		$this->afterFilter = new filterHolder($this);
		$this->afterFilter->addArray($this->config->get('globals', 'afterFilters'));
		$this->debug->write('Filters created');
		//Load the controller
					
		$cn = $this->routeVars['controller'].'Controller';
		$this->controller = new $cn($this);
		if($this->controller->getMode()!=AETHER_BOTH&&$this->controller->getMode()!=$this->mode) {
			$this->errorHandler->trigger('unauthorizedMode', array('controller' => $this->routeVars['controller'], 'action' => $this->routeVars['action'], 'mode' => $this->mode, 'module' => $this->module));
		}
		if(isset($this->controller->beforeFilters)&&$this->controller->beforeFilters!=array()) {		
			$this->beforeFilter->addArray($this->controller->beforeFilters);
		}
		if(isset($this->controller->afterFilters)&&$this->controller->afterFilters!=array()) {		
			$this->afterFilter->addArray($this->controller->afterFilters);
		}
		$this->debug->write('Controller created and initialized');
		
		//Run the action
		$action = urlToPHP($this->routeVars['action']);
		if(!method_exists($this->controller, $action)) {
			$this->errorHandler->trigger('noMatchingAction', array('controller' => $this->routeVars['controller'], 'action' => $action));
		}
		$this->beforeFilter->trigger();
		$this->debug->write('Before filter triggered');
		$this->controller->$action();
		$this->debug->write('Action run');
		$this->afterFilter->trigger();
		$this->debug->write('After filter triggered');
		
		//Create the veiw and run it
		if($this->controller->hasView()) {
			$this->view = new view($this);
		}
		$this->debug->write('View created and displayed');
		$this->debug->write('--------------------------');
		$this->debug->write('');
	}

	function getRawUrl() {
		return $this->rawUrl;
	}

	function getUrl() {
		return $this->url;
	}

	function getMode() {
		return $this->mode;
	}

	function getRouteVars() {
		return $this->routeVars;
	}
	
	function load($name) {
		if(isset($this->debug)) {
			$this->debug->write('File "'.$name.'" loaded');
		}
		require_once('aether/'.$name.'.php');
	}
	
	function __destruct() {
		if($this->mode==AETHER_CLI)
			echo NL;
	}

	function loadClasses($classes) {
		foreach($classes as $class) {
			if(file_exists('app/classes/'.$class.'.php')) {
				require_once('app/classes/'.$class.'.php');
			} else if(file_exists('core/classes/'.$class.'.php')) {
				require_once('core/classes/'.$class.'.php');
			} else {
				die('Class '.$class.' could not be loaded');
			}
		}
	}

	function loadClass($class) {
		$this->loadClasses(array($class));
	}

	function getModule() {
		return $this->module;
	}
};

//A canvas class, used for storing variables
class canvas {};

?>
